/*
 * Caller.cpp
 *
 *  Created on: Jul 7, 2009
 *      Author: lfor
 */

#include "Caller.h"

Caller::Caller() : Initialized(0), CallySock(0)
{
}

int Caller::Initialize(char * InetAddr, int PortNum)
{
	if (!Initialized)
	{
	    // Argument parsing
		if (InetAddr == NULL)
		{
			return(CALLER_INVALID_PARAM);
		}

		if (PortNum == 0)
		{
			PortNum = DEFAULT_PORT;
		}

		// Create socket to cally
		CallySock = socket(AF_INET, SOCK_STREAM, 0);
		if (CallySock < 0)
		{
		   return(CALLER_SOCKET_ERROR);
		}

		// Connect
		bzero((char *) &CallyAddr, sizeof(CallyAddr));
		CallyAddr.sin_family = AF_INET;
		CallyAddr.sin_addr.s_addr = inet_addr(InetAddr);
		CallyAddr.sin_port = htons(PortNum);

		if (connect(CallySock, (struct sockaddr *) &CallyAddr, sizeof(CallyAddr)) < 0)
		{
			return(CALLER_CANNOT_CONNECT);
		}

		Initialized = 1;
	}

	return(CALLER_OK);
}

int Caller::Finalize()
{
	if (Initialized)
	{
		shutdown(CallySock, SHUT_RDWR);
		CallySock = 0;

		Initialized = 0;
	}

	return(CALLER_OK);
}

int Caller::Close()
{
	int Ret = CALLER_OK;
	int Count = 0;
	char Buffer[MAX_BUFF_SIZE];

    // Prepare packet
    PacketType Packet;
    Packet.Status = CLOSE;
    Packet.Function[0] = 0;
	Packet.Params[0] = 0;
	Packet.Returns[0] = 0;
	Packet.Errors[0] = 0;
	Packet.DataLength = 0;
	Packet.Data = NULL;

    // send
	int BuffSize = MAX_BUFF_SIZE;
	if (FillBuffer(Packet, Buffer, &BuffSize) != PACKET_OK)
	{
			return(CALLER_ERROR);
	}

	//printf("CALLER SEND: \n%s\n",Buffer);

    Count = send(CallySock, Buffer, BuffSize, 0);
    if (Count <= 0)
    {
         return(CALLER_ERROR);
    }

    // Receive response
    Count = recv(CallySock, Buffer, MAX_BUFF_SIZE, 0);
    if (Count <= 0)
    {
         return(CALLER_ERROR);
    }

	//printf("CALLER RECV: \n%s\n",Buffer);

    PacketType ReturnPacket;
    ParseBuffer(Buffer, MAX_BUFF_SIZE, &ReturnPacket);

    if (ReturnPacket.Status != CLOSE)
    {
    	Ret = CALLER_ERROR;
    }

	return(Ret);
}

int Caller::List(char * Buffer, int Length)
{
    int n = 0;

	// Check arguments
	if (Buffer == NULL)
	{
		return(CALLER_INVALID_PARAM);
	}

    // Prepare buffer to be sent
    bzero(Buffer, Length);

    // Prepare packet
    PacketType Packet;
    Packet.Status = LIST;
    Packet.Function[0] = 0;
	Packet.Params[0] = 0;
	Packet.Returns[0] = 0;
	Packet.Errors[0] = 0;
	Packet.DataLength = 0;
	Packet.Data = NULL;

   // send
	int Ret = 0;
	int BuffSize = Length;
	if ((Ret = FillBuffer(Packet, Buffer, &BuffSize)) != PACKET_OK)
	{
		if (Ret == PACKET_NOT_ENOUGH_BUFFER)
		{
			return(CALLER_NOT_ENOUGH_BUFFER);
		}
		else
		{
			return(CALLER_ERROR);
		}
	}

 	//printf("CALLER SEND: \n%s\n",Buffer);

    n = send(CallySock, Buffer, BuffSize, 0);
    if (n <= 0)
    {
         return(CALLER_ERROR);
    }

    // Receive response
    n = recv(CallySock, Buffer, Length, 0);
    if (n <= 0)
    {
         return(CALLER_ERROR);
    }

	//printf("CALLER RECV: \n%s\n",Buffer);

    PacketType ReturnPacket;
    ParseBuffer(Buffer, Length, &ReturnPacket);
    if ((ReturnPacket.Status == LIST) && (ReturnPacket.Data != NULL))
    {
    	strncpy(Buffer, ReturnPacket.Data, ReturnPacket.DataLength);
    	Buffer[ReturnPacket.DataLength] = 0;
    }

    return(CALLER_OK);
}

int Caller::Call(StatusType * Status, char * Name, char * Params, char * Returns, char * Errors, int DataSize, char * Data)
{
	char Buffer[MAX_BUFF_SIZE];
    int n = 0;

	// Check arguments
	if ((Name == NULL) || (Params == NULL) || (Status == NULL) || (Returns == NULL) || (Errors == NULL))
	{
		return(CALLER_INVALID_PARAM);
	}

    // Prepare buffer to be sent
    bzero(Buffer,MAX_BUFF_SIZE);

    // Prepare packet
    PacketType Packet;
    Packet.Status = CALL;

    n = strlen(Name);
    if ((n >= MAX_NAME_SIZE) || (n <= 0))
    {
    	return(CALLER_INVALID_PARAM);
    }
	strncpy(Packet.Function, Name, n);
	Packet.Function[n] = 0;

    n = strlen(Params);
    if ((n >= MAX_PARAM_SIZE) || (n < 0))
    {
    	return(CALLER_INVALID_PARAM);
    }
	strncpy(Packet.Params, Params, n);
	Packet.Params[n] = 0;

	Packet.Returns[0] = 0;
	Packet.Errors[0] = 0;

	if (DataSize > 0)
	{
		if (Data != NULL)
		{
			Packet.DataLength = DataSize;
			Packet.Data = Data;
		}
		else
		{
			return(CALLER_INVALID_PARAM);
		}
	}
	else
	{
		Packet.DataLength = 0;
	}

    // send
	int Ret = 0;
	int BuffSize = MAX_BUFF_SIZE;
	if ((Ret = FillBuffer(Packet, Buffer, &BuffSize)) != PACKET_OK)
	{
		if (Ret == PACKET_NOT_ENOUGH_BUFFER)
		{
			return(CALLER_NOT_ENOUGH_BUFFER);
		}
		else
		{
			return(CALLER_ERROR);
		}
	}

	//printf("CALLER SEND: \n%s\n",Buffer);

    n = send(CallySock, Buffer, BuffSize, 0);
    if (n <= 0)
    {
         return(CALLER_ERROR);
    }

    // Receive response
    n = recv(CallySock, Buffer, MAX_BUFF_SIZE, 0);
    if (n <= 0)
    {
         return(CALLER_ERROR);
    }

	//printf("CALLER RECV: \n%s\n",Buffer);

    ParseBuffer(Buffer, MAX_BUFF_SIZE, &Packet);

    if (Packet.Status == OK)
    {
    	*Status = OK;

        n = strlen(Packet.Returns);
    	strncpy(Returns, Packet.Returns, n);
    	Returns[n] = 0;
    }

    if (Packet.Status == ERROR)
    {
    	*Status = ERROR;

        n = strlen(Packet.Errors);
    	strncpy(Errors, Packet.Errors, n);
    	Errors[n] = 0;
    }


    return(CALLER_OK);
}
